<?php
	class DatabaseElement{
	/*
	@UPDATE
		Classe DatabaseElement - Version 0.1
		Auteur : Loïc "MetalFox" PARRA
		Classe mère de la gestion de tous les éléments dont les données proviennent d'une base de données.
		
		README :
		Un DatabaseElement est une représentation sous forme d'objet d'une ligne d'une base de données. Un DatabaseElement étant générique, cela peut-être de n'importe quelle base de données. Un DatabaseElement permet de se connecter a la base de données, de charger un tuple qui nous interesse, et de les manipuler ses données avant de les sauvegarder. Il permet aussi d'inserer de nouveaux tuples dans la base de données, ou de donner une interpretation graphique (affichage) a cet élément.
		Il est déconseillé d'utiliser la classe telle quelle. Il est préférable de la spécialiser.
		
		DEPENDANCES :
		- Bd.class.php : le fournisseur de connexion a la base de données doit impérativement hériter de cette classe.
		
		SUCRE SYNTAXIQUE :
		On peut afficher l'interpretation graphique d'un DatabaseElement grace à un echo (par défaut, cet affichage est simplement l'ensemble des noms des attributs et leur valeur).
		On peut acceder directement a une attribut grace a l'opérateur '->'.
		
		EXEMPLE D'UTILISATION :
		$myDBP = new Bd("host","log","pass","base");
		$myDBE = new DatabaseElement($myDBP,"myTable","myTableprimary_key",1); ==> Charge l'élément ayant pour identifiant 1 de la table myTable grace a $myDBP.
		echo $myDBE->myTableprimary_key ==> Affiche 1.
		$myDBE->anotherRow = "myValue" ==> Modifie la valeur du champ "anotherRow" en "myValue"
		$myDBE->save() ==> Sauvegarde les modifications dans la base de données.
		
		CHANGELOG :
		- 0.0 : Création de la classe
		- 0.1 : Dernière manip effectuée : ajout du mysql_insert_id lors des sauvegardes pour les auto-increment
	*/
		var $attributes;
		var $table;
		var $id;
		var $error;
		
		function DatabaseElement($table,$id=""){
			/*
				Constructeur. Si $this->attributes n'a pas été complété manuellement dans la spécialisation, on appelle la base de données pour connaitre le nom des champs (utile pour les tables destinées à être souvent modifiées, mais couteux en ressources).
				@param $table : Nom de la table de laquelle on veut extraire les données.
				@param $id : base sur laquelle on doit faire les requetes.
				@return : N/A (soulève une exception si le databaseProvider n'est pas bon).
			*/
			//TODO : pouvoir mettre les mustHave via le back office, et récupérer les types des champs
			try{
				$this->table = $table;
				$this->attributes = array();
				if(isset($GLOBALS['PHPFoxEngine']->dbFields[$this->table]['columns'])){
					/*foreach($GLOBALS['PHPFoxEngine']->dbFields[$this->table]['columns'] as $key => $data){
						$this->$key = "";
					}*/
					$this->attributes = $GLOBALS['PHPFoxEngine']->dbFields[$this->table]['columns'];
				}
				else
				{
					throw new Exception("DatabaseElement : Impossible de trouver la table ".$this->table.".");
				}
				$this->id = $id;
				if($this->id != ""){
					$this->load($this->id);	
				}
				$this->error = array();
			}
			catch(Exception $e)
			{
				echo "PHPFoxEngine Error : ".$e->getMessage();
			}
		}
		
		function create($array){
			/*
				Remplit les attributs d'un DatabaseElement a partir des données du tableau fournit en parametre. Les indices du tableau doivent correspondre aux attributs du DatabaseElement. Tout champ différent sera ignoré.
				@param $array : tableau indexé contenant les données a insérer.
				@return : N/A.
			*/
			foreach($array as $key => $value){
				if(isset($this->attributes[$key]) && $value != ""){
					$this->$key = htmlspecialchars($value);
				}
			}
		}
		
		function load($id){
			/*
				Charge l'élément dont l'identifiant correspond à celui passé en parametre.
				@param $id : identifiant du tuple a charger.
				@return : N/A.
			*/
			try{
				$this->id = $id;
				$result = $GLOBALS['PHPFoxEngine']->database->query("SELECT * FROM ".$this->table." WHERE ".$GLOBALS['PHPFoxEngine']->dbFields[$this->table]['primary_key']." = '".$this->id."' LIMIT 1;");
				if(mysql_num_rows($result) < 1) throw new Exception("DatabaseElement : la requête de chargement n'a pas renvoyé de résultat.");
				$attributes = mysql_fetch_assoc($result);
				foreach($attributes as $key => $value){
					$this->$key = $value;
				}
			}
			catch (Exception $e)
			{
				echo "PHPFoxEngine Error : ".$e->getMessage();
			}
		}
		
		function save(){
			/*
				Enregistre le DatabaseElement dans la base de données. Si l'identifiant n'est pas renseigné, un nouveau tuple sera créé. Sinon, seule la mise a jour sera éffectuée.
				@param : N/A.
				@return : N/A.
			*/
			if($this->id == ""){
				$this->id = $this->attributes[$GLOBALS['PHPFoxEngine']->dbFields[$this->table]['primary_key']]['value'];
				if(!$GLOBALS['PHPFoxEngine']->database->query("INSERT INTO ".$this->table." (".$GLOBALS['PHPFoxEngine']->dbFields[$this->table]['primary_key'].") VALUES ('".$this->id."');")) return false;
				$lastid = mysql_insert_id();
				if($lastid != 0) $this->id = $lastid;
			}
			$query = "UPDATE ".$this->table." SET ";
			foreach($GLOBALS['PHPFoxEngine']->dbFields[$this->table]['columns'] as $key => $value) if($this->$key != '') $query .= $key." = '".addslashes($this->$key)."',";
			$query = substr($query,0,strlen($query) - 1);
			$query .= " WHERE ".$GLOBALS['PHPFoxEngine']->dbFields[$this->table]['primary_key']." = '".$this->id."';";
			return $GLOBALS['PHPFoxEngine']->database->query($query);
		}
		
		function check(){ //TODO : tester
			foreach($this->attributes as $key => $value){
				if($value['nullable'] == 'NO' && $this->$key == "") $this->error[$key]= "Ce champ est obligatoire";
				else if(($value['nullable'] == 'NO' && $this->$key != "") && ($value['type'] == "tinyint" || $value['type'] == "int") && !is_numeric($this->$key)) $this->error[$key]= "Ce champ doit être renseigné avec un nombre";
			}
			return empty($this->error);
		}
		
		function error($field){
			return (isset($this->error[$field]))? '<span class="error">'.$this->error[$field].'</span>':"";
		}
		
		public function __set($nomAttribut, $valeurAttribut)
		{
			/*
				Surcharge de la Magic Method __set. Permet d'affecter un attribut sans utiliser la notation de tableau ($this->attribute['monattribut'] = myValue).
				@param $nomAttribut : nom de l'attribut a affecter.
				@param $valeurAttribut : valeur a attribuer.
				@return : N/A.
			*/
			$this->attributes[$nomAttribut]['value'] = $valeurAttribut;
		}

		public function __get($nomAttribut)
		/*
			Surcharge de la Magic Method __get. Permet d'acceder a un attribut sans utiliser la notation de tableau ($this->attribute['monattribut']).
			@param $name : nom de l'attribut a chercher.
			@return : L'attribut appelé (soulève une exception si l'attribut n'existe pas).
		*/
		{
			try{
				if (!array_key_exists($nomAttribut, $this->attributes)) {
					throw new Exception("DatabaseElement : '".$nomAttribut."' n'est pas un attribut.");
				}
				if(!isset($this->attributes[$nomAttribut]['value'])) throw new Exception("DatabaseElement : '".$nomAttribut."' n'a pas de valeur (value) définie.");
				return $this->attributes[$nomAttribut]['value'];
			}
			catch (Exception $e)
			{
				echo "PHPFoxEngine Error : ".$e->getMessage();
			}
		}
		
		public function __toString(){
			/*
				Surcharge de la Magic Method __toString. Permet d'afficher le DatabaseElement.
				@param : N/A.
				@return : l'affichage du DatabaseElement.
			*/
			$string = "";
			foreach($this->attributes as $key => $value){
				$string .= $key." => ".$this->$key."<br/>";
			}
			return $string;
		}
		
		public function formHelp(){
			$form = htmlspecialchars('<form action="" method="post">');
			foreach($this->attributes as $key => $value){
				$form .= htmlspecialchars('<label for="'.$key.'">'.$key.'</label><input type="text" name="'.$key.'" id="'.$key.'" value="<?php echo $this->'.$key.'; ?>" /><?php echo $this->error(\''.$key.'\'); ?><br/>');
			}
			$form .= htmlspecialchars('<input type="submit" name="submit" value="Envoyer"></form>');
			return $form;
		}
	}
?>